home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / text.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  60KB  |  2,470 lines

  1. /*
  2.  * $Id: text.c,v 0.91 1994/02/20 00:53:02 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  *  Purpose:
  26.  *    Place arbitrary text on the image with automatic font switching to get
  27.  *    Greek letters, with same input method as in TeX.
  28.  *
  29.  * Needs a lot of more cleanup and abstraction. Also, this routine
  30.  * does its own SaveUnders. Without support like X Pixmap, it is hard
  31.  * to avoid framebuffer read.
  32.  *
  33.  * Moving text around is by default done via a simulated double buffereing
  34.  * mechanism, which unfortunately could be slow on R3k or slower machines.
  35.  *
  36.  * BUGS: there is a leak in fontcache to avoid a bug in the fontmanager
  37.  * (on IRIX 4.0.5 only ?), currently replying on font cache flushing to
  38.  * limit the leak.
  39.  *
  40.  *
  41.  */
  42. #if !defined(lint) && defined(F_ID)
  43. char *id_text = "$Id: text.c,v 0.91 1994/02/20 00:53:02 zhao Pre-Release $";
  44. #endif
  45.  
  46. #include "bit.h"
  47. #include "fmclient.h"
  48. #include "extern.h"
  49. #include "dmalloc.h"
  50.  
  51. #ifndef NO_FM_BUG
  52. #define FM_BUG
  53. #endif
  54.  
  55. #include "symbol.h"        /* fonts and special symbols     */
  56. #include "tsdef.h"        /* Token defination              */
  57.  
  58. /***************** Limits and defines ****************************/
  59.  
  60. #define MINFSIZE  3.0        /* min fontsize allowd              */
  61. #define MAXFSIZE  150.0        /* max fontsize allowd              */
  62. #define MAXTEXT   31        /* max strings per image            */
  63. #define MAXFONT   25        /* max no. of fonts                 */
  64. #define MAXSTR    512        /* max string length                */
  65. #define SSHIFT    1        /* shadow shift                     */
  66. #define SSTEP     15        /* every sstep increase shadow by 1 */
  67. #define BW        1        /* for engrave & embossed             */
  68.  
  69. /* if requested font in particular size is not availble, the font
  70.    manager substitutes another one, and thus the bounding box
  71.    maybe wrong. Add EXTRA to the bounding box to guarantee cleanup
  72.  */
  73. #define EXTRA     15        /* extra space for bounding box    */
  74.  
  75. #define TC        0        /* text color index       */
  76. #define FC        1        /* frame color index      */
  77. #define BC        2        /* bk color index         */
  78.  
  79. /*************** Local variables    ******************************/
  80.  
  81. static fmfonthandle fh[MAXFONT];/* All 1pt sized fonts         */
  82. static char *fontname[MAXFONT];    /* and their names             */
  83.  
  84. static int mfindex;        /* math(symbol) font index      */
  85. static fmfonthandle mathfont[5];/* in different sizes           */
  86. static fmfonthandle textfont[5];/* text font in different sizes */
  87. static int pmatch;        /* if use printer width info    */
  88.  
  89. static int immediate = 1;    /* default rendering method     */
  90. static int placement = 1;    /* alignment                    */
  91. static Line cline;        /* current line                 */
  92.  
  93. static IPTR limg;        /* local copy of image pointer  */
  94.  
  95. /** Special effects */
  96. enum seffects
  97.   {
  98.       SE_normal, SE_shadow, SE_engraved, SE_embossed
  99.   };
  100.  
  101. static const char *seffect_name[] =
  102. {
  103.     "Normal", "Shadow", "Engraved", "Embossed", 0
  104. };
  105.  
  106. /* size command and corresponding font size delta */
  107. static const char *size_cmd[] =
  108. {
  109.     "normal", "tiny", "small", "large", "huge"
  110. };
  111.  
  112. static float fdelta[] =
  113. {
  114.     0, -4, -2, 2, 4
  115. };
  116.  
  117. /***************************************************************
  118.  * Text structure. Positions are relative to the the rasterimage
  119.  **************************************************************/
  120. typedef struct
  121.   {
  122.       char *str;        /* input string              */
  123.       Line *line;        /* tokenized string          */
  124.       int findex;        /* index into fh             */
  125.       fmfonthandle cfont;    /* scaled, ready to use      */
  126.       int xi, yi;        /* starting position >0      */
  127.       int xt, yt;        /* with proper justi         */
  128.       int w, h;            /* repaint region            */
  129.       float size;        /* text size int points      */
  130.       float rot;        /* rot angle 0 <rot <360     */
  131.       int col[3][4];        /* text, bk and frame color  */
  132.       int colm[4];        /* scaled with factor < 1    */
  133.       int colp[4];        /* scaled with factor > 1    */
  134.       short height;        /* font height               */
  135.       short slant;        /* slant in x dir            */
  136.       short descent;        /* slant in y dir            */
  137.       short frame;        /* if put a frame on         */
  138.       short bk;            /* if frame and bk           */
  139.       short place;        /* 0 l, 1 c, 2 r             */
  140.       short se;            /* if shadow                 */
  141.   }
  142. Text_t;
  143.  
  144. static Text_t textbuf[MAXTEXT];    /* text saved            */
  145. static Text_t cttext;        /* working buf           */
  146. static Text_t *tptr = &cttext;    /* current text line     */
  147. static char strbuf[MAXSTR + 2];    /* plus cursor + '\0'    */
  148.  
  149. static int xi, yi, xf, yf;    /* rectangular bounds */
  150. static float vec[4][2];        /* rotated coordinats */
  151.  
  152. static int lxi, lyi, lxf, lyf;    /* For saveunder */
  153.  
  154. /******************* Local functions ***************************/
  155.  
  156. static Line *getlinemem(void);
  157. static void dupline(Line *, const Line *);
  158. static void freeline(Line *);
  159. static void sim_dbl_text_move(Text_t *);
  160. static void sgl_text_move(Text_t *);
  161. static void dbl_text_move(Text_t *);
  162. static void text_rasterize(Text_t *);
  163.  
  164. static void
  165. save_last_position(void)
  166. {
  167.     lxi = xi - EXTRA;
  168.     lyi = yi - EXTRA;
  169.     lxf = xf + EXTRA;
  170.     lyf = yf + EXTRA;
  171. }
  172.  
  173.  
  174. /****************************************************************
  175.  * Find next availale slot
  176.  ****************************************************************/
  177.  
  178. static Text_t *
  179. text_next(void)
  180. {
  181.     register Text_t *tx = textbuf + MAXTEXT;
  182.  
  183.     while (--tx >= textbuf && tx->line)
  184.     ;
  185.  
  186.     if (tx < textbuf)
  187.       {
  188.       M_err("NextText", "out of bounds");
  189.       return 0;
  190.       }
  191.     return tx;
  192. }
  193.  
  194. /*****************************************************************
  195.  * save current text (tptr) into the structure
  196.  *****************************************************************/
  197. static int
  198. text_save(void)
  199. {
  200.     Text_t *tx = text_next();
  201.  
  202.     if (tx)            /* ok */
  203.       {
  204.       memcpy(tx, tptr, sizeof(*tx));
  205.  
  206.       tx->str = strdup(strbuf);
  207.       tx->line = getlinemem();
  208.       dupline(tx->line, &cline);
  209.  
  210.       /* convert to image distance based */
  211.       tx->xi -= limg->xi;
  212.       tx->yi -= limg->yi;
  213.       }
  214.     return tx ? 0 : -1;
  215. }
  216.  
  217. /****************************************************************
  218.  * Remove a saved text
  219.  *****************************************************************/
  220. static void
  221. text_free(Text_t * t)
  222. {
  223.     if (t)
  224.       {
  225.       if (t->str)
  226.           free(t->str);
  227.       freeline(t->line);
  228.       t->line = 0;
  229.       }
  230. }
  231.  
  232. /********************************************************************
  233.  * Total number of text saved so far. Also re-arranges text
  234.  * in a consecutive manner
  235.  *******************************************************************/
  236. static Text_t *ttt[MAXTEXT];
  237. int
  238. number_of_text(void)
  239. {
  240.     register int i = 0;
  241.     register Text_t *tx = textbuf + MAXTEXT;
  242.  
  243.     while (--tx >= textbuf)
  244.     if (tx->line)
  245.         ttt[i++] = tx;
  246.     return i;
  247. }
  248.  
  249.  
  250.  
  251. /******************************************************************
  252.  * get line width, taking into account of font change and size change
  253.  *******************************************************************/
  254. static int
  255. get_line_width(Line * line)
  256. {
  257.     int i;
  258.     Token *t = line->token;
  259.     int tw = 0;
  260.  
  261.     for (i = line->ntokens; --i >= 0; t++)
  262.       {
  263.       tw += fmgetstrwidth(t->math ?
  264.                mathfont[t->isize] : textfont[t->isize], t->str);
  265.       }
  266.     return tw;
  267. }
  268.  
  269. /*****************************************************************
  270.  * Check if current font is the same as the last: Free all fonts
  271.  * used if different and setnewfonts will re-generate needed fonts.
  272.  ****************************************************************/
  273. static int
  274. font_diff(Text_t * t)
  275. {
  276.     int diff;
  277.     static int cfindex = -1;    /* cache for last font */
  278.     static float csize = -1.0;    /* cache for last font */
  279.     static lpmatch = -1;
  280.  
  281.     diff = ((cfindex != t->findex) ||    /* diff font */
  282.         (lpmatch != pmatch) ||    /* diff font */
  283.         (Abs(csize - t->size) > 0.1));    /* diff size */
  284.  
  285.     /*
  286.      * free the old font if different. Can't do this because IRIX 4.05? has a
  287.      * bug that will produce a segmentation fault
  288.      */
  289.  
  290.     if (diff)
  291.       {                /* not first time */
  292.  
  293. #ifndef FM_BUG            /* The workaround */
  294.       if (cfindex >= 0)
  295.         {
  296.         int i;
  297.         for (i = 0; i < 5; i++)
  298.           {
  299.               fmfreefont(mathfont[i]);
  300.               fmfreefont(textfont[i]);
  301.           }
  302.         }
  303. #endif
  304.  
  305.       cfindex = t->findex;
  306.       lpmatch = pmatch;
  307.       csize = t->size;
  308.       }
  309.     return diff;
  310. }
  311.  
  312.  
  313. /***********************************************************
  314.  * Set text and math font for possible different sizes
  315.  ***********************************************************/
  316. static void
  317. set_new_font(Text_t * t)
  318. {
  319.     static fmfontinfo info;
  320.     long owin = winget();
  321.     static fmfonthandle lcfont;    /* scaled, ready to use   */
  322.     float tmpfsize[6], tt;
  323.     int i;
  324.     float *tf = tmpfsize, *td = fdelta;
  325.  
  326.     /* set new font only if different from last */
  327.     if (font_diff(t))
  328.       {
  329.  
  330.       /* get all the sizes */
  331.       *tf++ = (tt = t->size + *td++) > 1.0 ? tt : MINFSIZE;
  332.       *tf++ = (tt = t->size + *td++) > 1.0 ? tt : MINFSIZE;
  333.       *tf++ = (tt = t->size + *td++) > 1.0 ? tt : MINFSIZE;
  334.       *tf++ = (tt = t->size + *td++) > 1.0 ? tt : MINFSIZE;
  335.       *tf = (tt = t->size + *td) > 1.0 ? tt : MINFSIZE;
  336.  
  337.       /* validate all used fonts */
  338.       for (i = 0; i < 5; i++)
  339.         {
  340.         mathfont[i] = fmscalefont(fh[mfindex], tmpfsize[i]);
  341.         textfont[i] = fmscalefont(fh[t->findex], tmpfsize[i]);
  342.         }
  343.  
  344.       /* current font */
  345.       t->cfont = lcfont = textfont[0];
  346.  
  347.       M_info("SetNewFont", "FontCacheused: %ld", fmgetcacheused());
  348.  
  349.       /* install font */
  350.       set_current_window(win_id);
  351.       fmsetfont(t->cfont);
  352.       fmgetfontinfo(t->cfont, &info);
  353.       }
  354.  
  355.     /* record basic properties */
  356.     t->cfont = lcfont;
  357.     t->descent = info.yorig;
  358.     t->slant = info.xorig;
  359.     t->height = info.height - t->descent + 1;
  360.     if (owin > 0)
  361.     set_current_window(owin);
  362. }
  363.  
  364. /********************************************************************
  365.  * Find the box that encloses the text for repaint. VEC[4][i] are
  366.  * the rotated  coordinates of the box that bounds the text
  367.  * while (xi, yi), (xf, yf) are the  coordinates of the bounding box
  368.  * that bounds everything.
  369.  *
  370.  * the unrotated bounding box:
  371.  *
  372.  * (-slant , h)              (w + shift, h)
  373.  * (-slant, descent)         (w+shift, descent)
  374.  *******************************************************************/
  375. static double pagematrix[3][2];
  376. #include <math.h>
  377. #define PI   3.1415926
  378. static void
  379. get_bounding_box(Text_t * t)
  380. {
  381.     float sina, cosa;
  382.     int i, sshift;
  383.     float xo, yo;
  384.     int ww, hh;            /* the true width of text */
  385.     float cxo, sxo, cyo, syo;
  386.     float cww, sww, chh, shh;
  387.     float xsf, ysf;
  388.  
  389.  
  390.     /* basic size */
  391.     t->w = get_line_width(t->line) + t->size / 5;
  392.     t->h = t->height;
  393.  
  394.     /* calculate the shift caused by special effects */
  395.  
  396.     if (t->se == SE_shadow)
  397.       {
  398.       sshift = (SSHIFT + (t->size / SSTEP));
  399.       xo = -(t->slant + 1);
  400.       yo = -(t->descent + 1) - sshift - 1;
  401.       ww = t->w + sshift;
  402.       hh = t->h;
  403.       }
  404.     else if (t->se == SE_normal)
  405.       {
  406.       sshift = 0;
  407.       xo = -(t->slant + 1);
  408.       yo = -(t->descent + 1) - sshift - 2;
  409.       ww = t->w;
  410.       hh = t->h;
  411.       }
  412.     else
  413.       {
  414.       sshift = 1.0;
  415.       xo = -(t->slant + 1) - 1;
  416.       yo = -(t->descent + 1) - sshift - 2;
  417.       ww = t->w + 2;
  418.       hh = t->h + 2;
  419.       }
  420.  
  421.  
  422.     cosa = cos(t->rot * (PI / 180.0));
  423.     sina = sin(t->rot * (PI / 180.0));
  424.  
  425.     cww = cosa * ww;
  426.     sww = sina * ww;
  427.  
  428.     t->xt = t->xi;
  429.     t->yt = t->yi;
  430.  
  431.     if (t->place == TCENTER)
  432.       {                /* center */
  433.       xsf = 0.5 * cww;
  434.       ysf = 0.5 * sww;
  435.       }
  436.     else if (t->place == TRIGHT)
  437.       {                /* left adjusted */
  438.       xsf = cww;
  439.       ysf = sww;
  440.       }
  441.     else
  442.       {
  443.       xsf = 0.0;
  444.       ysf = 0.0;
  445.       }
  446.  
  447.     t->xt -= xsf;
  448.     t->yt -= ysf;
  449.  
  450.     /* get the rotated coordinates for the  4pt */
  451.     /* (xo, yo) */
  452.     vec[0][0] = (cxo = cosa * xo) - (syo = sina * yo) + t->xt;
  453.     vec[0][1] = (sxo = sina * xo) + (cyo = cosa * yo) + t->yt;
  454.  
  455.     /* (w + shift, yo) */
  456.     vec[1][0] = cww - syo + t->xt;
  457.     vec[1][1] = sww + cyo + t->yt;
  458.  
  459.     /* (ww, h) */
  460.     vec[2][0] = cww - (shh = sina * hh) + t->xt;
  461.     vec[2][1] = sww + (chh = cosa * hh) + t->yt;
  462.  
  463.     /* (xo, h) */
  464.     vec[3][0] = cxo - shh + t->xt;
  465.     vec[3][1] = sxo + chh + t->yt;
  466.  
  467.  
  468.     /* get lower-left and upper-right */
  469.     xi = xf = vec[0][0];
  470.     yi = yf = vec[0][1];
  471.     for (i = 1; i < 4; i++)
  472.       {
  473.       if (xi > vec[i][0])
  474.           xi = vec[i][0];
  475.       if (xf < vec[i][0])
  476.           xf = vec[i][0];
  477.       if (yi > vec[i][1])
  478.           yi = vec[i][1];
  479.       if (yf < vec[i][1])
  480.           yf = vec[i][1];
  481.       }
  482.  
  483.     /* enlarge by 1 on all sides */
  484.     xi--;
  485.     yi--;
  486.     xf++;
  487.     yf++;
  488. }
  489.  
  490. /********************************************************************
  491.  * Generate a framebox
  492.  *******************************************************************/
  493. static void
  494. make_frame(Text_t * t)
  495. {
  496.     int i;
  497.  
  498.     if (t->bk)
  499.       {
  500.       Color4(t->col[BC]);
  501.       bgnpolygon();
  502.       for (i = 0; i < 4; i++)
  503.           v2f(vec[i]);
  504.       endpolygon();
  505.       }
  506.  
  507.     if (t->frame)
  508.       {
  509.       Color4(t->col[FC]);
  510.       bgnclosedline();
  511.       for (i = 0; i < 4; i++)
  512.           v2f(vec[i]);
  513.       endclosedline();
  514.       }
  515. }
  516.  
  517. /**********************************************************************
  518.  * We have the option to clean up the text by saving the screen or repaint
  519.  * with the raster matrix depending on the definition of READSCR
  520.  *
  521.  * Do not know about Indigo, supposedly repeated read and write degrade the
  522.  * image and in that case READSCR should be undefined.
  523.  **********************************************************************/
  524.  
  525. #define READSCR
  526.  
  527. static void **spp;
  528.  
  529. /****************************************************************
  530.  * do a SaveUnder. If READSCR is not defined, we can use the image
  531.  * in core as the backing store, save_under does nothing
  532.  ***************************************************************/
  533. static void
  534. save_under(void)
  535. {
  536.  
  537. #ifdef READSCR
  538.  
  539.     static int lsxi, lsyi, lsxf, lsyf;
  540.     int moved;
  541.  
  542.     moved = (lxi - lsxi) || (lyi - lsyi) || (lxf - lsxf) || (lyf - lsyf);
  543.  
  544.     if (moved || !spp)
  545.       {
  546.  
  547.       lsxi = lxi;
  548.       lsyi = lyi;
  549.       lsxf = lxf;
  550.       lsyf = lyf;
  551.       free_mat(spp);
  552.       spp = get_mat(lyf - lyi + 1, lxf - lxi + 1, imgptr->esize);
  553.       set_current_window(win_id);
  554.       Rectread(lxi, lyi, lxf, lyf, spp[0]);
  555.       }
  556.  
  557. #endif
  558. }
  559.  
  560. static void
  561. restore_piece(int txi, int tyi, int txf, int tyf)
  562. {
  563.     if (txi != txf && spp)
  564.       {
  565.       set_current_window(win_id);
  566.       reshapeviewport();
  567. #ifdef READSCR
  568.  
  569.       PI_rectwrite(txi, tyi, txf, tyf, spp[0]);
  570. #else
  571.  
  572.       img_rect_redraw(limg, txi, tyi, txf - txi + 1, tyf - tyi + 1);
  573. #endif
  574.  
  575.       }
  576. }
  577.  
  578. /****************************************************************
  579.  * The actuall routine that does the rendering at given location.
  580.  * It does not rememeber where it did it.
  581.  ****************************************************************/
  582. static void
  583. render_line(int x, int y, Line * line)
  584. {
  585.     Token *t = line->token, *ts;
  586.     static int lastmath = -1;
  587.     static float lastsize = -1.0;
  588.  
  589.     set_current_window(win_id);
  590.     reshapeviewport();
  591.     cmov2i(x, y);
  592.     for (ts = t + line->ntokens; t < ts; t++)
  593.       {
  594.       if (lastmath != t->math || Abs(lastsize - t->size) > 0.1)
  595.         {
  596.         fmsetfont(t->math ? mathfont[t->isize] : textfont[t->isize]);
  597.         }
  598.       fmprstr(t->str);
  599.       }
  600. }
  601.  
  602. /**********************************************************************
  603.  * Routine takes care of frame and rotation and call render_line to
  604.  * do the actual rendering
  605.  *********************************************************************/
  606. static void
  607. text_draw_only(Text_t * t)
  608. {
  609.     int sshift = (SSHIFT + (t->size / SSTEP)) * (t->se != SE_normal);
  610.  
  611.     set_current_window(win_id);
  612.     reshapeviewport();
  613.  
  614.     if (t->bk || t->frame)
  615.     make_frame(t);
  616.  
  617.     if (t->rot >= 0.1)
  618.       {
  619.       fmgetpagematrix(pagematrix);
  620.       fmrotatepagematrix(t->rot);
  621.       }
  622.  
  623.     if (t->se == SE_shadow)
  624.       {
  625.       scale_color(t->col[TC], 0.3, t->colm, 0, PCMAXV);
  626.       Color4(t->colm);
  627.       render_line(t->xt + sshift, t->yt - sshift, t->line);
  628.       }
  629.     else if (t->se == SE_engraved)
  630.       {
  631.       scale_color(t->col[TC], 0.3, t->colm, 80, PCMAXV);
  632.       scale_color(t->col[TC], 2.0, t->colp, 200, PCMAXV);
  633.       Color4(t->colm);
  634.       render_line(t->xt - BW, t->yt + BW, t->line);
  635.       Color4(t->colp);
  636.       render_line(t->xt + BW, t->yt - BW, t->line);
  637.       }
  638.     else if (t->se == SE_embossed)
  639.       {
  640.       scale_color(t->col[TC], 0.3, t->colm, 80, PCMAXV);
  641.       scale_color(t->col[TC], 2.0, t->colp, 200, PCMAXV);
  642.       Color4(t->colp);
  643.       render_line(t->xt - BW, t->yt + BW, t->line);
  644.       Color4(t->colm);
  645.       render_line(t->xt + BW, t->yt - BW, t->line);
  646.       }
  647.  
  648.     /* the real text */
  649.     Color4(t->col[TC]);
  650.     render_line(t->xt, t->yt, t->line);
  651.  
  652.     /* Restore the pagematrix and free fontcache used */
  653.     if (t->rot >= 0.1)
  654.       {
  655.       fmsetpagematrix(pagematrix);
  656.       }
  657.  
  658. }
  659.  
  660. /********************************************************************
  661.  * Draw and show
  662.  ********************************************************************/
  663. static void
  664. text_draw(Text_t * t)
  665. {
  666.  
  667.     text_draw_only(t);
  668.  
  669. #ifndef SGL_BUF
  670.     if (double_buf)
  671.       {
  672.       swapbuffers();
  673.       }
  674. #endif
  675. }
  676.  
  677. /*****************************************************************
  678.  * This routine takes care of rendering and moving, i.e., remember
  679.  * where we did it.
  680.  *****************************************************************/
  681. static void
  682. sgl_text_move(Text_t * t)
  683. {
  684.  
  685.     /* repaint the region where old text was */
  686.     restore_piece(lxi, lyi, lxf, lyf);
  687.  
  688.     /* need to do this everytime to get the correct box */
  689.     get_bounding_box(t);
  690.  
  691.     /* remember where we will do it */
  692.     save_last_position();
  693.     save_under();
  694.     text_draw_only(t);
  695. }
  696.  
  697. /*****************************************************************
  698.  * move text in double buffer mode
  699.  *****************************************************************/
  700. static int lastwme;
  701. static void
  702. dbl_text_move(Text_t * t)
  703. {
  704.  
  705.     /* need to do this everytime to get the correct box */
  706.     get_bounding_box(t);
  707.  
  708.     /*
  709.      * all text has the back buffer completely clean except when window
  710.      * manager does the redraw, need to clean up the back buffer when last
  711.      * redraw is wme
  712.      */
  713.  
  714.     if (lastwme)
  715.       {
  716.       restore_piece(lxi, lyi, lxf, lyf);
  717.       lastwme = 0;
  718.       }
  719.     /* remember where we will do it */
  720.     text_draw(t);
  721.     restore_piece(lxi, lyi, lxf, lyf);
  722.     save_last_position();
  723.     save_under();
  724. }
  725.  
  726. static void
  727. text_move(Text_t * t)
  728. {
  729.     long owin = winget();
  730.     set_current_window(win_id);
  731.     reshapeviewport();
  732.  
  733.     /*
  734.      * can't use sim_dbl_buffer here because the need to completely redraw
  735.      * the text string
  736.      */
  737.  
  738.     (double_buf ? dbl_text_move : sgl_text_move) (t);
  739.  
  740.     if (owin > 0)
  741.     set_current_window(owin);
  742. }
  743.  
  744. /********************************************************************
  745.  * This is the routine that sets new font (font family, size, rotation)
  746.  *********************************************************************/
  747. static void
  748. render_text(Text_t * t)
  749. {
  750.     if (!t || !t->line)
  751.     return;
  752.     set_new_font(t);
  753.     text_move(t);
  754. }
  755.  
  756. /*********************************************************************
  757.  * initialize all fonts and get the font handle. Remove unavailable font
  758.  * names
  759.  ********************************************************************/
  760. static int
  761. init_fonts(void)
  762. {
  763.     int i;
  764.     static int n = -1;
  765.  
  766.     if (n > 0)
  767.     return n;
  768.  
  769.     if (totalfont > MAXFONT)
  770.       {
  771.       totalfont = MAXFONT - 1;
  772.       }
  773.  
  774.     fminit();
  775.  
  776.     /*
  777.      * there are leaks currently, we need to make sure cache is large enuf,
  778.      * about 2M
  779.      */
  780.  
  781. #ifdef FM_BUG
  782.     fmsetcachelimit((1500 * 1000) / FMCACHE_QUANTUM);
  783. #endif
  784.  
  785.     fmcacheenable();
  786.  
  787.     n = i = 0;
  788.     while (i < totalfont)
  789.       {
  790.       if ((fh[n] = fmfindfont(fonts[i])))
  791.         {
  792.         fontname[n] = fonts[i];
  793.         if (strcmp(fontname[n], "Symbol") == 0)
  794.             mfindex = n;
  795.         n++;
  796.         }
  797.       i++;
  798.       }
  799.     fontname[n] = 0;
  800.     return totalfont = n;
  801. }
  802.  
  803. /*******************************************************************
  804.  * Given a fontname fn, try to get the font index, findfont return.
  805.  * If fn is bad, first available font index is returned.
  806.  * MUST not return bogus index. On a related note, it is best
  807.  * to have the first font index entry be a mon-spaced font.
  808.  *******************************************************************/
  809. static int
  810. get_font_index(const char *fn)
  811. {
  812.     int found, i;
  813.  
  814.     if (!init_fonts())
  815.       {
  816.       Bark("InitText", "Unable to load any fonts!!");
  817.       return 0;
  818.       }
  819.     if (!fn || !*fn)
  820.     return 0;
  821.  
  822.     i = -1;
  823.     do
  824.       {
  825.       i++;
  826.       found = strcmp(fontname[i], fn) == 0;
  827.       }
  828.     while (!found && i < totalfont - 1);
  829.     return found ? i : 0;
  830. }
  831.  
  832. /*******************************************************************
  833.  * Support routines that parse the input string into tokens with many
  834.  * attributes
  835.  *****************************************************************{*/
  836. /* allocate memory for struct Line */
  837. static Line *
  838. getlinemem(void)
  839. {
  840.     /* assuming char * has all zero bits for null */
  841.     return calloc(1, sizeof(Line));
  842. }
  843.  
  844. /* make a copy of struct line */
  845. static void
  846. dupline(Line * to, const Line * from)
  847. {
  848.     const Token *t = from->token, *ts;
  849.     Token *pt = to->token;
  850.  
  851.     if (!memcpy(to, from, sizeof(*from)))
  852.     return;
  853.  
  854.     /* we are not done yet, members of line malloced */
  855.     for (ts = t + from->ntokens; t < ts; t++, pt++)
  856.     if (t->str)
  857.         pt->str = strdup(t->str);
  858.     return;
  859. }
  860.  
  861. /* Free all memory allocated for a line */
  862. static void
  863. freeline(Line * line)
  864. {
  865.     Token *t, *ts;
  866.  
  867.     if (!line)
  868.     return;
  869.  
  870.     for (t = line->token, ts = t + line->ntokens; t < ts; t++)
  871.       {
  872.       if (t->str)
  873.           free(t->str);
  874.       t->str = 0;
  875.       }
  876. }
  877.  
  878. #ifdef SC_DEBUG
  879. static void
  880. print_tokens(Line * line)
  881. {
  882.     int c;
  883.  
  884.     fprintf(stderr, "Total %d tokens\n", line->ntokens);
  885.     for (c = 0; c < line->ntokens; c++)
  886.     fprintf(stderr, "math=%d size=%.1f is=%d str=%s^\n",
  887.         line->token[c].math, line->token[c].size,
  888.         line->token[c].isize, line->token[c].str);
  889. }
  890.  
  891. #endif
  892.  
  893.  
  894.  
  895. /*************************************************************
  896.  * check if a particular token is a sizing command, i.e.,
  897.  * \small, \large etc
  898.  **************************************************************/
  899. static int
  900. is_size(const char *p)
  901. {
  902.     int i;
  903.     for (i = sizeof(size_cmd) / sizeof(char *); --i >= 0;)
  904.     if ((size_cmd[i][0] == *p) && strcmp(size_cmd[i], p) == 0)
  905.         return i;
  906.     return -1;
  907. }
  908.  
  909. /******************************************************************
  910.  * Add a new token to line and fix the special symbols on the fly
  911.  * sz is the base size while isize is index into the modifier
  912.  *******************************************************************/
  913. #include <ctype.h>
  914. static void
  915. new_token(Line * line, int m, float sz, int isize, char *str)
  916. {
  917.     register char *s = str;
  918.     char token[MAXSTR], ltok[MAXSTR];
  919.     char *ct, *lct;
  920.     Token *t = &line->token[line->ntokens];
  921.  
  922.     if (!*str)
  923.     return;
  924.  
  925.     t->math = m;
  926.     if (isize < 0)
  927.     isize = 0;
  928.     t->isize = isize;
  929.     t->size = sz + fdelta[isize];
  930.     /* there is no point print a string you can't see */
  931.     if (t->size < MINFSIZE)
  932.     t->size = MINFSIZE;
  933.  
  934.     if (t->str)
  935.     free(t->str);
  936.  
  937.     ct = token;
  938.     while (*s)
  939.       {
  940.       switch (*s)
  941.         {
  942.         case '\\':
  943.         lct = ltok;
  944.         while (*++s && isalnum(*s))
  945.             *lct++ = *s;
  946.         *lct = '\0';
  947.         *ct = '\0';
  948.         /* mathcode returns a string of length 1 or more */
  949.         strcat(token, m ? mathcode(ltok) : spcode(ltok));
  950.         ct = token + strlen(token);
  951.         --s;
  952.         break;
  953.         default:
  954.         *ct++ = *s;
  955.         break;
  956.         }
  957.       if (*s)
  958.           s++;
  959.       }
  960.     *ct = '\0';
  961.     t->str = strdup(token);
  962.     line->ntokens++;
  963.     if (line->ntokens >= MAXTOK)
  964.       {
  965.       M_warn("TextAddToken", "No. of tokens out of bounds");
  966.       line->ntokens = MAXTOK - 1;
  967.       }
  968. }
  969.  
  970. /**********************************************************************
  971.  * Break a line into tokens. A token is defined as a string uninterrupted
  972.  * by font switching ($) or size change \small etc
  973.  * Base size is sz
  974.  **********************************************************************/
  975. static void
  976. tokenize(char *str, Line * line, float sz)
  977. {
  978.     register char *p = str;
  979.     register char *ct, *lct;
  980.     register int math = 0;
  981.     float size = sz;
  982.     int isize = 0;
  983.     register int c;
  984.     char ctoken[MAXSTR], ltoken[MAXSTR];
  985.  
  986.     line->ntokens = 0;
  987.     ct = ctoken;
  988.     ltoken[0] = '\0';
  989.  
  990.     while (p && *p)
  991.       {
  992.       switch (*p)
  993.         {
  994.         case '$':
  995.         *ct = '\0';
  996.         new_token(line, math, size, isize, ctoken);
  997.         ct = ctoken;
  998.         math = !math;
  999.         break;
  1000.         case '\\':
  1001.         c = *++p;    /* skip  \\ */
  1002.         if (c == '\\' || c == '$')
  1003.           {        /* escape */
  1004.               *ct++ = c;
  1005.           }
  1006.         else if (c)
  1007.           {        /* a true token.  */
  1008.               lct = ltoken;
  1009.               *lct++ = '\\';
  1010.               *lct++ = c;
  1011.               while (*++p && isalpha(*p))
  1012.               *lct++ = *p;
  1013.               *lct = '\0';
  1014.               /* check if sizing command */
  1015.               if ((c = is_size(ltoken + 1)) >= 0)
  1016.             {
  1017.                 *ct = '\0';
  1018.                 new_token(line, math, size, isize, ctoken);
  1019.                 isize = c;
  1020.                 ct = ctoken;
  1021.             }
  1022.               else
  1023.             {    /* not a size command, keep it */
  1024.                 *lct = '\0';
  1025.                 *ct = '\0';
  1026.                 strcat(ctoken, ltoken);
  1027.                 ct = ctoken + strlen(ctoken);
  1028.             }
  1029.               --p;    /* backup */
  1030.           }
  1031.         break;
  1032.         default:
  1033.         *ct++ = *p;
  1034.         }
  1035.       if (*p)
  1036.           p++;
  1037.       }
  1038.     *ct = '\0';
  1039.  
  1040.     if (math)
  1041.     M_info("ScanLine", "Unfinished math");
  1042.  
  1043.     if (math)
  1044.       {
  1045.       /* show only complete symbols */
  1046.       p = (ct = strrchr(ctoken, ' ')) ? ct : strrchr(ctoken, '\\');
  1047.       if (p)
  1048.           *p = '\0';
  1049.       }
  1050.     new_token(line, math, size, isize, ctoken);
  1051. #ifdef SC_DEBUG
  1052.     print_tokens(line);
  1053. #endif
  1054. }
  1055.  
  1056. /***********************************************************************
  1057.  * END OF SUPPORT ROUTINES
  1058.  *******************************************************************}*/
  1059.  
  1060. /*
  1061.  * routine to add text. To be called non-interactively.
  1062.  */
  1063. void
  1064. img_add_text(IPTR im, const char *s, const char *f,
  1065.          float tsize, float trot, rgba_t tc, int x, int y, int bk,
  1066.          rgba_t bc, int fr, rgba_t fc, int sh, int pl)
  1067. {
  1068.     Text_t *t;
  1069.     int i, r, g, b;
  1070.  
  1071.     if (!im || !s)
  1072.     return;
  1073.  
  1074.     t = text_next();
  1075.     memset(t, 0, sizeof(*t));
  1076.     t->line = getlinemem();
  1077.     t->str = strdup(s);
  1078.     t->place = 0;
  1079.     t->xi = x;
  1080.     t->yi = y;
  1081.  
  1082.     Unpack(tc, r, g, b);
  1083.     t->col[TC][0] = r;
  1084.     t->col[TC][1] = g;
  1085.     t->col[TC][2] = b;
  1086.  
  1087.     Unpack(fc, r, g, b);
  1088.     t->col[FC][0] = r;
  1089.     t->col[FC][1] = g;
  1090.     t->col[FC][2] = b;
  1091.  
  1092.     Unpack(bc, r, g, b);
  1093.     t->col[BC][0] = r;
  1094.     t->col[BC][1] = g;
  1095.     t->col[BC][2] = b;
  1096.  
  1097.     if (IS_CI(im))
  1098.       {
  1099.       for (i = 0; i < 3; i++)
  1100.           t->col[i][3] = cmap_closematch(im->cmap, t->col[i][0],
  1101.                          t->col[i][1], t->col[i][2]);
  1102.       }
  1103.  
  1104.     t->bk = bk;
  1105.     t->frame = fr;
  1106.     t->size = tsize;
  1107.     t->rot = trot;
  1108.     t->findex = get_font_index(f);
  1109.     t->se = sh;
  1110.     t->place = pl;
  1111.     tokenize(t->str, t->line, t->size);
  1112. }
  1113.  
  1114.  
  1115. const char *
  1116. get_text_fontname(int nt)
  1117. {
  1118.     return fontname[ttt[nt]->findex];
  1119. }
  1120.  
  1121. float
  1122. get_text_fontsize(int nt)
  1123. {
  1124.     return ttt[nt]->size;
  1125. }
  1126.  
  1127. const char *
  1128. get_text_string(int nt)
  1129. {
  1130.     return ttt[nt]->str;
  1131. }
  1132.  
  1133. Line *
  1134. get_text_line(int nt)
  1135. {
  1136.     return ttt[nt]->line;
  1137. }
  1138.  
  1139. int
  1140. get_text_placement(int nt)
  1141. {
  1142.     return ttt[nt]->place;
  1143. }
  1144.  
  1145. void
  1146. get_text_location(int nt, int *x, int *y)
  1147. {
  1148.     *x = ttt[nt]->xi;
  1149.     *y = ttt[nt]->yi;
  1150. }
  1151.  
  1152. float
  1153. get_text_rotation(int nt)
  1154. {
  1155.     return ttt[nt]->rot;
  1156. }
  1157.  
  1158. int
  1159. get_fm_cache(void)
  1160. {
  1161.     return (fmcachelimit() * FMCACHE_QUANTUM / 1000);
  1162. }
  1163.  
  1164. int
  1165. get_fm_cacheused(void)
  1166. {
  1167.     return (fmgetcacheused() / 1000);
  1168. }
  1169.  
  1170. /*************************************************************************
  1171.  * get max sizes of texts that sticks out of the image, only approximately
  1172.  * by using mono space and ignoring rotation
  1173.  ************************************************************************/
  1174. void
  1175. get_text_bounds(IPTR im, int *top, int *left, int *bottom, int *right)
  1176. {
  1177.     Text_t *tx = textbuf + MAXTEXT;
  1178.     int l = 0, b = 0, t = im->h, r = im->w;
  1179.  
  1180.     while (--tx >= textbuf)
  1181.       {
  1182.       ;            /* to be written  */
  1183.       }
  1184.     *top = t - im->h;
  1185.     *left = -l;
  1186.     *bottom = -b;
  1187.     *right = r - im->w;
  1188. }
  1189.  
  1190. /*
  1191.  * can't use limg because this routine can be called anywhere
  1192.  */
  1193. void
  1194. get_text_color(int nt, int *r, int *g, int *b)
  1195. {
  1196.     int i;
  1197.  
  1198.     if (IS_CI(imgptr))
  1199.       {
  1200.       i = ttt[nt]->col[TC][3];
  1201.       *r = imgptr->cmap->ct[0][i];
  1202.       *g = imgptr->cmap->ct[0][i];
  1203.       *b = imgptr->cmap->ct[0][i];
  1204.       }
  1205.     else
  1206.       {
  1207.       *r = ttt[nt]->col[TC][0];
  1208.       *g = ttt[nt]->col[TC][1];
  1209.       *b = ttt[nt]->col[TC][2];
  1210.       }
  1211. }
  1212.  
  1213. /*
  1214.  * Delete all text saved and free all spaces
  1215.  */
  1216. void
  1217. del_text(void)
  1218. {
  1219.     Text_t *tx = textbuf + MAXTEXT;
  1220.  
  1221.     while (--tx >= textbuf)
  1222.       {
  1223.       if (!tx->line)
  1224.           continue;
  1225.       text_free(tx);
  1226.       }
  1227. }
  1228.  
  1229. /******************************************************************
  1230.  * Display current saved text.
  1231.  *
  1232.  *  This routine could be called by various routines, including
  1233.  *  display, or window resizing events handlers. In any case,
  1234.  *  this routine should not alter buffer settings (back, front etc).
  1235.  ******************************************************************/
  1236.  
  1237. static int active;        /* true if entered thru do_text */
  1238. void
  1239. display_text(IPTR im)
  1240. {
  1241.     Text_t *t = textbuf + MAXTEXT;
  1242.  
  1243.     init_text();
  1244.  
  1245.     /* If bad image,  silently return */
  1246.     if (im->ok <= 0)
  1247.     return;
  1248.  
  1249.     while (--t >= textbuf)
  1250.       {
  1251.       if (t->line)
  1252.         {
  1253.         t->xi += im->xi;
  1254.         t->yi += im->yi;
  1255.         set_new_font(t);
  1256.         get_bounding_box(t);
  1257.         text_draw_only(t);
  1258.         t->xi -= im->xi;
  1259.         t->yi -= im->yi;
  1260.         }
  1261.       }
  1262.  
  1263.     /*
  1264.      * active means we are currently in text mode, and therefore need to
  1265.      * re-draw the current text as well
  1266.      */
  1267.  
  1268.     if (active)
  1269.       {
  1270.       set_new_font(tptr);
  1271.       sgl_text_move(tptr);
  1272.       lastwme = 1;
  1273.       }
  1274. }
  1275.  
  1276.  
  1277. /***********************************************************************
  1278.  * Save to and restore from disk. Could've dumped the whole structure out,
  1279.  * but ASCII will be portable.
  1280.  */
  1281. void
  1282. dump_text(FILE * fp)
  1283. {
  1284.     Text_t *t = textbuf + MAXTEXT;
  1285.  
  1286.     fprintf(fp, "#TX %d\n", number_of_text());
  1287.     /* can't stick # in front */
  1288.     fputs(" Font Size Rot Text_t Tc Bc Fc X Y bk fr sh just\n", fp);
  1289.  
  1290.     while (--t >= textbuf)
  1291.       {
  1292.       if (!t->line)
  1293.           continue;
  1294.       fprintf(fp, "#%s %.2f %.1f\n", fonts[t->findex], t->size, t->rot);
  1295.       fprintf(fp, "%s\n", t->str);
  1296.       fprintf(fp, "%g %g %g %g %g %g %g %g %g\n",
  1297.           C2NC(t->col[0][0]), C2NC(t->col[0][1]), C2NC(t->col[0][2]),
  1298.           C2NC(t->col[1][0]), C2NC(t->col[1][1]), C2NC(t->col[1][2]),
  1299.         C2NC(t->col[2][0]), C2NC(t->col[2][1]), C2NC(t->col[2][2]));
  1300.       fprintf(fp, "%d %d %d %d %d %d \n", t->xi, t->yi, t->bk, t->frame,
  1301.           t->se, t->place);
  1302.       }
  1303. }
  1304.  
  1305. /**********************************************************
  1306.  *  load text from disk.
  1307.  ***********************************************************/
  1308. void
  1309. load_text(IPTR im)
  1310. {
  1311.     int n, i, j;
  1312.     char fname[60], *p;
  1313.     float fsize, trot, f;
  1314.     int x, y, r, g, b;
  1315.     rgba_t cc[3];
  1316.     int bk, fr, sh, pl;
  1317.     FILE *fp = im->fp;
  1318.  
  1319.     while ((n = getc(fp)) != EOF && n != '#')
  1320.     ;
  1321.     if (n != '#' || (n = getc(fp) != 'T') || (n = getc(fp)) != 'X')
  1322.     return;
  1323.  
  1324.     n = readpint(fp);
  1325.  
  1326.     if (n <= 0)
  1327.     return;
  1328.     if (n >= MAXTEXT)
  1329.       {                /* can't happen */
  1330.       Bark("LoadText", "Total %d strings %s", n, outbound);
  1331.       return;
  1332.       }
  1333.     M_info("LoadText", "%d strings found", n);
  1334.  
  1335.     for (i = 0; i < n; i++)
  1336.       {
  1337.       while (fgets(strbuf, MAXSTR, fp) && strbuf[0] != '#')
  1338.           ;
  1339.       if (strbuf[0] != '#')
  1340.         {
  1341.         M_warn("LoadText", "More are expected");
  1342.         return;
  1343.         }
  1344.       sscanf(strbuf + 1, "%s %f %f", fname, &fsize, &trot);
  1345.       fgets(strbuf, MAXSTR, fp);
  1346.       /* remove newline */
  1347.       if ((p = strchr(strbuf, '\n')))
  1348.           *p = '\0';
  1349.       for (j = 0; j < 3; j++)
  1350.         {
  1351.         f = readfloat(fp);
  1352.         r = NC2C(f);
  1353.         f = readfloat(fp);
  1354.         g = NC2C(f);
  1355.         f = readfloat(fp);
  1356.         b = NC2C(f);
  1357.         cc[j] = Pack(r, g, b);
  1358.         }
  1359.       x = readint(fp);
  1360.       y = readint(fp);
  1361.       bk = readint(fp);
  1362.       fr = readint(fp);
  1363.       sh = readint(fp);
  1364.       pl = readint(fp);
  1365.       img_add_text(im, strbuf, fname, fsize, trot, cc[TC],
  1366.                x, y, bk, cc[BC], fr, cc[FC], sh, pl);
  1367.       }
  1368. }
  1369.  
  1370. /********************************************************************
  1371.  * convert text to gray. need only change the RGB representation.
  1372.  * This routine is called after a type conversion
  1373.  ********************************************************************/
  1374. void
  1375. text_to_gray(void)
  1376. {
  1377.     register int q;
  1378.     Text_t *t = textbuf + MAXTEXT;
  1379.     int *cc;
  1380.  
  1381.     while (--t >= textbuf)
  1382.       {
  1383.       if (!t->line)
  1384.           continue;
  1385.  
  1386.       cc = t->col[TC];
  1387.       q = rgb2gray(cc[0], cc[1], cc[2]);
  1388.       cc[0] = cc[1] = cc[2] = q;
  1389.  
  1390.       cc = t->col[BC];
  1391.       q = rgb2gray(cc[0], cc[1], cc[2]);
  1392.       cc[0] = cc[1] = cc[2] = q;
  1393.  
  1394.       cc = t->col[FC];
  1395.       q = rgb2gray(cc[0], cc[1], cc[2]);
  1396.       cc[0] = cc[1] = cc[2] = q;
  1397.  
  1398.       }
  1399. }
  1400.  
  1401. /*************************************************************
  1402.  * Convert text color from RGB based to index based. Called
  1403.  * after image type conversion, i.e., quantization. Not
  1404.  * possible to honour exact colors, do the best we can
  1405.  * from the colormap.
  1406.  *************************************************************/
  1407. void
  1408. text_to_cmap(void)
  1409. {
  1410.     Text_t *t = textbuf + MAXTEXT;
  1411.     int *cc;
  1412.  
  1413.     if (!IS_CI(imgptr))
  1414.     return;
  1415.  
  1416.     while (--t >= textbuf)
  1417.       {
  1418.       if (!t->line)
  1419.           continue;
  1420.  
  1421.       cc = t->col[TC];
  1422.       cc[3] = cmap_closematch(imgptr->cmap, cc[0], cc[1], cc[2]);
  1423.  
  1424.       cc = t->col[BC];
  1425.       cc[3] = cmap_closematch(imgptr->cmap, cc[0], cc[1], cc[2]);
  1426.  
  1427.       cc = t->col[FC];
  1428.       cc[3] = cmap_closematch(imgptr->cmap, cc[0], cc[1], cc[2]);
  1429.  
  1430.       }
  1431. }
  1432.  
  1433. /************************************************************
  1434.  *
  1435.  * GUI part of the Text routines.
  1436.  *
  1437.  * Fills the Text_t structure and show its effect
  1438.  *
  1439.  ************************************************************/
  1440.  
  1441. #define MINTXSIZE 1.0        /* minimum text size */
  1442. #define TXSTEP1   1.0        /* minimum delta     */
  1443. #define TXSTEP2   5.0        /* maximum delta     */
  1444.  
  1445. /*ARGSUSED */
  1446. static void
  1447. immediate_cb(FL_OBJECT * ob, long q)
  1448. {
  1449.     immediate = fl_get_choice(ob) - 1;
  1450. }
  1451.  
  1452. /* default size for shortcuts */
  1453. static const float fsize[] =
  1454. {
  1455.     5.0, 8.0, 10.0, 12.0, 14.0, 20.0
  1456. };
  1457.  
  1458. /* default shortcuts for orientation */
  1459. static const float rangle[] =
  1460. {
  1461.     0, 90, 180, 270
  1462. };
  1463.  
  1464. static int indexs = 2;        /* default size index  */
  1465. static int indexr;        /* default orientation */
  1466. static FL_FORM *textform;
  1467. static FL_OBJECT *fchoice;
  1468. static FL_OBJECT *input, *rcounter, *scounter, *effects;
  1469. static FL_OBJECT *col[3], *frame, *bk, *size[6], *ra[4];
  1470.  
  1471. /*********************************************************
  1472.  * Initialize fonts, form entries, etc
  1473.  *********************************************************/
  1474. static void create_form_text(void);
  1475. int
  1476. init_text(void)
  1477. {
  1478.     int i;
  1479.     char **p;
  1480.     char tmp[20];
  1481.     static int init;
  1482.     static const char *dirtext[] =
  1483.     {
  1484.     "Horiz", "90", "180", "-90"
  1485.     };
  1486.  
  1487.     if (init > 0)
  1488.     return init;
  1489.  
  1490.     show_busy("LoadingFonts ...");
  1491.  
  1492.     /* find all fonts */
  1493.     if (!init_fonts())
  1494.       {
  1495.       Bark("InitText", "Unable to load any fonts!!");
  1496.       return -1;
  1497.       }
  1498.  
  1499.     init = totalfont;
  1500.     create_form_text();
  1501.  
  1502.     /* fill the font choices */
  1503.     fl_clear_choice(fchoice);
  1504.     for (p = fontname; p && *p; p++)
  1505.     fl_addto_choice(fchoice, *p);
  1506.     fl_set_choice(fchoice, 1);
  1507.  
  1508.  
  1509.     /* cleanr all size buttons  and set default */
  1510.     for (i = 0; i < 6; i++)
  1511.       {
  1512.       fl_set_button(size[i], 0);
  1513.       sprintf(tmp, "%.0fpt", fsize[i]);
  1514.       fl_set_object_label(size[i], tmp);
  1515.       }
  1516.     fl_set_button(size[indexs], 1);
  1517.  
  1518.     /* set size counter default for arbitrary size */
  1519.     fl_set_counter_precision(scounter, 1);
  1520.     fl_set_counter_bounds(scounter, MINTXSIZE, MAXFSIZE);
  1521.     fl_set_counter_step(scounter, TXSTEP1, TXSTEP2);
  1522.     fl_set_counter_value(scounter, fsize[indexs]);
  1523.  
  1524.     /* cleanr all rotation buttons  and set default */
  1525.     for (i = 0; i < 4; i++)
  1526.       {
  1527.       fl_set_button(ra[i], 0);
  1528.       fl_set_object_label(ra[i], dirtext[i]);
  1529.       }
  1530.     fl_set_button(ra[indexr], 1);
  1531.  
  1532.     /* set rotation counter default */
  1533.     fl_set_counter_precision(rcounter, 0);
  1534.     fl_set_counter_bounds(rcounter, 0.0, 360.0);
  1535.     fl_set_counter_step(rcounter, 1, 10);
  1536.     fl_set_counter_value(rcounter, rangle[indexr]);
  1537.  
  1538.     /* misc */
  1539.     fl_set_button(frame, 0);
  1540.     fl_set_button(bk, 0);
  1541.     fl_set_input_return(input, 1);
  1542.     end_busy();
  1543.     return init;
  1544. }
  1545.  
  1546.  
  1547. /*********************************************************************
  1548.  * default Text color, Frame color and background color
  1549.  ********************************************************************/
  1550. static int lcol[][4] =
  1551. {
  1552.     {0, 0, 0, 0},        /* text color       */
  1553.     {PCMAXV, 0, 0, 1},        /* frame color      */
  1554.     {PCMAXV, PCMAXV, PCMAXV, 0}    /* background color */
  1555. };
  1556.  
  1557.  
  1558. /*****************************************************************
  1559.  * Every time do_text is called, this routine will be called to set
  1560.  * current  size, color etc.
  1561.  *****************************************************************/
  1562. static void
  1563. set_text_default(Text_t * t)
  1564. {
  1565.     int i;
  1566.  
  1567.     strcpy(strbuf, limg->ifile);
  1568.     fl_set_input(input, strbuf);
  1569.  
  1570.     t->size = fl_get_counter_value(scounter);
  1571.     t->findex = fl_get_choice(fchoice) - 1;
  1572.     t->frame = fl_get_button(frame);
  1573.     t->se = fl_get_choice(effects) - 1;
  1574.     t->bk = fl_get_button(bk);
  1575.     t->rot = fl_get_counter_value(rcounter);
  1576.     t->place = placement;
  1577.     t->xi = win_w / 2 - 10;
  1578.     t->yi = win_h / 2 - 10;
  1579.  
  1580.     for (i = 0; i < 4; i++)
  1581.       {
  1582.       t->col[TC][i] = lcol[0][i];
  1583.       t->col[FC][i] = lcol[1][i];
  1584.       t->col[BC][i] = lcol[2][i];
  1585.       }
  1586.     tokenize(strbuf, t->line, t->size);
  1587. }
  1588.  
  1589.  
  1590. /***********************************************************
  1591.  * Handle mouse events: Depending on various options,
  1592.  * either double buffer, simulated double buffer and single
  1593.  * buffer mode will be used. Note that in defered mode, current
  1594.  * code is not capable of simulating double buffering without
  1595.  * messing up the screen
  1596.  **********************************************************/
  1597. static void
  1598. handle_mouse(Text_t * t)
  1599. {
  1600.     void (*moveit) (Text_t *);
  1601.     int mx, my;
  1602.  
  1603.     if (!double_buf && simu_dbl_buffer && immediate)
  1604.     text_rasterize(t);
  1605.  
  1606.     /* hardware double buffering overrites other settings */
  1607.     moveit = double_buf ? dbl_text_move :
  1608.     ((simu_dbl_buffer && immediate) ? sim_dbl_text_move : sgl_text_move);
  1609.  
  1610.     M_info("TextMouse", moveit == dbl_text_move ? "DoubleBuffer" :
  1611.        (moveit == sim_dbl_text_move ?
  1612.         "SimuDblBuffer" : "SglBuffer"));
  1613.  
  1614.     do
  1615.       {
  1616.       WHERE_R2W(mx, my, win_xo, win_yo);
  1617.       if (mx != t->xi || my != t->yi)
  1618.         {
  1619.         show_mouse_position(mx, my);
  1620.         t->xi = mx;
  1621.         t->yi = my;
  1622.         moveit(t);
  1623.         }
  1624.       }
  1625.     while (mouse_down);
  1626.  
  1627.     if (!double_buf && simu_dbl_buffer && immediate)
  1628.       {
  1629.       free_mat(spp);
  1630.       spp = no_fail_get_subimage(imgptr, lxi, lyi,
  1631.                      lxf - lxi + 1, lyf - lyi + 1);
  1632.       }
  1633. }
  1634.  
  1635. /*****************************************************************
  1636.  * Simulate double buffering
  1637.  *****************************************************************/
  1638. static int diffcolor;
  1639. #ifndef NO_NP_DBL        /* { */
  1640. static void **rastext;
  1641. static int rash, rasw;
  1642.  
  1643. static int
  1644. attribute_diff(Text_t * t)
  1645. {
  1646.     static float rotated = -1;
  1647.     static int lframe = -1, lbk = -1;
  1648.     static char lstrbuf[MAXSTR + 2];    /* plus cursor + '\0'    */
  1649.     static int leffects = -1;
  1650.     int diff;
  1651.  
  1652.     diff = (t->bk - lbk) ||    /* diff background */
  1653.     (t->frame - lframe) ||    /* diff frame */
  1654.     (Abs(t->rot - rotated) > 0.5) || diffcolor ||
  1655.     (t->se - leffects) || strcmp(lstrbuf, strbuf);
  1656.  
  1657.     if (diff)
  1658.       {
  1659.       lbk = t->bk;
  1660.       lframe = t->frame;
  1661.       rotated = t->rot;
  1662.       leffects = t->se;
  1663.       diffcolor = 0;
  1664.       strcpy(lstrbuf, strbuf);
  1665.       }
  1666.     return diff;
  1667. }
  1668.  
  1669. static int
  1670. bad_magic_pix(rgba_t m)
  1671. {
  1672.     if (IS_CPACK(imgptr))
  1673.       {
  1674.       rgba_t txc, bkc, fmc;
  1675.  
  1676.       txc = Pack(lcol[TC][0], lcol[TC][1], lcol[TC][2]);
  1677.       bkc = Pack(lcol[BC][0], lcol[BC][1], lcol[BC][2]);
  1678.       fmc = Pack(lcol[FC][0], lcol[FC][1], lcol[FC][2]);
  1679.       return (m == txc || m == bkc || m == fmc);
  1680.       }
  1681.     else
  1682.       {
  1683.       return (m == lcol[TC][3] ||
  1684.           m == lcol[BC][3] ||
  1685.           m == lcol[FC][3]);
  1686.       }
  1687. }
  1688.  
  1689. /**********************************************************************
  1690.  * Rasterize a text string: reads the screen buffer. Someday,
  1691.  * it should be replaced with feekback from the GE.
  1692.  * only should be called within handle_mouse
  1693.  **********************************************************************/
  1694. static void
  1695. text_rasterize(Text_t * t)
  1696. {
  1697.     static int incomplete;
  1698.     static int cfindex = -1;
  1699.     static int csize = -1.0;
  1700.     static int lpmatch = -1;
  1701.     rgba_t magicpix = 0;
  1702.  
  1703.     /* can't simple use font_diff because render_text sets it */
  1704.     int diff = ((cfindex != t->findex) ||    /* diff font */
  1705.         (lpmatch != pmatch) ||    /* diff font */
  1706.         (Abs(csize - t->size) > 0.1));    /* diff size */
  1707.  
  1708.     /* if no backing store, can't rasterize */
  1709.     if (lxi == lxf || !spp)
  1710.       {
  1711.       M_err("TextRasterize", "Failed to rasterize");
  1712.       return;
  1713.       }
  1714.  
  1715.     if (!attribute_diff(t) && !diff && !incomplete && rastext)
  1716.     return;
  1717.  
  1718.     /* if last is incomplete, need to re-generate the text */
  1719.     if ((incomplete = (lxi <= 0 || lyi <= 0 || lxf >= win_w || lyf >= win_h)))
  1720.       {
  1721.       int mx, my;
  1722.  
  1723.       WHERE_R2W(mx, my, win_xo, win_yo);
  1724.       t->xi = mx;
  1725.       t->yi = my;
  1726.       sgl_text_move(t);
  1727.       }
  1728.  
  1729.     rasw = lxf - lxi + 1;
  1730.     rash = lyf - lyi + 1;
  1731.     M_info("RasterizeText", "w=%d h=%d", rasw, rash);
  1732.  
  1733.     free_mat(rastext);
  1734.     rastext = get_mat(rash, rasw, imgptr->esize);
  1735.  
  1736.  
  1737.     PI_rectread(lxi, lyi, lxf, lyf, rastext[0]);
  1738.     PI_rectwrite(lxi, lyi, lxf, lyf, spp[0]);
  1739.  
  1740.     /*
  1741.      * check to make sure that the magic pixel is NOT one of the text color,
  1742.      * background color or framecolor
  1743.      */
  1744.     while (bad_magic_pix(magicpix))
  1745.     magicpix++;
  1746.  
  1747.     set_magic_pix(magicpix);
  1748.  
  1749.     if (IS_CPACK(imgptr))
  1750.       {
  1751.       rgba_t *p, *q, *qs;
  1752.  
  1753.       /* rasterize */
  1754.       p = spp[0];
  1755.       q = rastext[0];
  1756.       qs = q + rash * rasw;
  1757.  
  1758.       while (q < qs)
  1759.         {
  1760.         *q = (*q == *p) ? magicpix : *q;
  1761.         q++;
  1762.         p++;
  1763.         }
  1764.       }
  1765.     else
  1766.       {
  1767.       ci_t *p, *q, *qs;
  1768.       /* rasterize */
  1769.       p = spp[0];
  1770.       q = rastext[0];
  1771.       qs = q + rash * rasw;
  1772.  
  1773.       while (q < qs)
  1774.         {
  1775.         *q = (*q == *p) ? magicpix : *q;
  1776.         q++;
  1777.         p++;
  1778.         }
  1779.       }
  1780.  
  1781.     cfindex = t->findex;
  1782.     csize = t->size;
  1783.     lpmatch = pmatch;
  1784.  
  1785.     if (incomplete)
  1786.       {
  1787.       text_draw(t);
  1788.       }
  1789.     /* update for possible sgl_text_move call */
  1790.     incomplete = (lxi <= 0 || lyi <= 0 || lxf >= win_w || lyf >= win_h);
  1791.  
  1792. }
  1793.  
  1794. static void
  1795. sim_dbl_text_move(Text_t * t)
  1796. {
  1797.  
  1798.     if (!rastext)
  1799.       {
  1800.       text_move(t);
  1801.       return;
  1802.       }
  1803.     get_bounding_box(t);
  1804.     sim_dbl_swap(imgptr, rasw, rash, rastext,
  1805.          xi - EXTRA, yi - EXTRA, lxi - EXTRA, lyi - EXTRA, O_MASK);
  1806.     save_last_position();
  1807. }
  1808.  
  1809. #endif /* } */
  1810. /*********************************************************************
  1811.  * In addition of saving current text
  1812.  * NL indicates move the current text "down" 1 line
  1813.  *********************************************************************/
  1814. static void
  1815. save_text(int nl)
  1816. {
  1817.     int k = strlen(strbuf);
  1818.  
  1819.     /* if empty string, do nothing */
  1820.     if (k == 0)
  1821.     return;
  1822.  
  1823.  
  1824.     if (immediate)
  1825.       {                /* need to render it into raster */
  1826.       set_current_window(win_id);
  1827.       if (double_buf)
  1828.           text_draw(tptr);
  1829.       fb_to_ras(limg, make_rect(lxi, lyi, lxf - lxi + 1, lyf - lyi - 1));
  1830.       if (!spp)
  1831.           spp = get_mat(lyf - lyi + 1, lxf - lxi + 1, limg->esize);
  1832.       Rectread(lxi, lyi, lxf, lyf, spp[0]);
  1833.       }
  1834.     else
  1835.       {
  1836.       text_save();        /* save it to structure */
  1837.  
  1838.       /*
  1839.        * do it one more time so that next save under will not screw up
  1840.        * the move
  1841.        */
  1842.       lxi = lxf = -1;
  1843.       text_draw(tptr);
  1844.       }
  1845.  
  1846.     /* requested nextline, figure out where it should be */
  1847.     if (nl)
  1848.       {
  1849.       float dh = 1.02 * tptr->height;
  1850.       tptr->xi += dh * sin(tptr->rot * PI / 180.0);
  1851.       tptr->yi -= dh * cos(tptr->rot * PI / 180.0);
  1852.       lxi = lxf = -1;
  1853.       text_move(tptr);
  1854.       }
  1855. }
  1856.  
  1857. /******************************************************************
  1858.  * wm_handler is called by repaint to handle unknown repaint
  1859.  * events from the window manager, e.g., resize, position change etc.
  1860.  ******************************************************************/
  1861. static int
  1862. text_wm_handler(IPTR im, int wme)
  1863. {
  1864.     static int imxi, imyi;
  1865.  
  1866.     if (wme > 0)
  1867.       {
  1868.       tptr->xi += (im->xi - imxi);
  1869.       tptr->yi += (im->yi - imyi);
  1870.       lxi += (im->xi - imxi);
  1871.       lyi += (im->yi - imyi);
  1872.       lxf += (im->xi - imxi);
  1873.       lyf += (im->yi - imyi);
  1874.       }
  1875.  
  1876.     imxi = im->xi;
  1877.     imyi = im->yi;
  1878.  
  1879.     /*
  1880.      * display text at the new location will be taken care of by
  1881.      * display_text, which is called by the dispatcher in do_repaint
  1882.      */
  1883.     return 0;
  1884. }
  1885.  
  1886. /***********************************************************
  1887.  * Process keyboard input
  1888.  ***********************************************************/
  1889. static int
  1890. text_keybd(Text_t * t, int val)
  1891. {
  1892.     int ret = 0;
  1893.     static int step = 1;
  1894.  
  1895.     switch (val)
  1896.       {
  1897.       case 'h':
  1898.       case 'H':
  1899.       t->xi -= step;
  1900.       break;
  1901.       case 'j':
  1902.       case 'J':
  1903.       t->yi -= step;
  1904.       break;
  1905.       case 'k':
  1906.       case 'K':
  1907.       t->yi += step;
  1908.       break;
  1909.       case 'l':
  1910.       case 'L':
  1911.       t->xi += step;
  1912.       break;
  1913.       case 27:
  1914.       ret = -1;
  1915.       break;
  1916.       default:
  1917.       if (val > '0' && val <= '9')
  1918.           step = val - '0';
  1919.       ret = 1;
  1920.       break;
  1921.       }
  1922.  
  1923.     if (ret >= 0)
  1924.       {
  1925.       text_move(tptr);
  1926.       ret = 0;
  1927.       }
  1928.     return ret;
  1929. }
  1930.  
  1931. /*******************************************************
  1932.  * This is the global entry point
  1933.  ********************************************************/
  1934. int
  1935. do_text(IPTR im)
  1936. {
  1937.     short val;
  1938.     int done;
  1939.  
  1940.     if (init_text() <= 0)
  1941.     return -1;
  1942.  
  1943.     install_wm_handler(text_wm_handler);
  1944.     text_wm_handler(im, 0);    /* initialize position */
  1945.  
  1946.     limg = im;
  1947.     lastwme = 0;
  1948.  
  1949.     bit_show_form(textform, FL_PLACE_MOUSE, 0, "Text");
  1950.     active = 1;
  1951.  
  1952.     /*
  1953.      * setting lxi < 0 effectively prevents the text rendering routine from
  1954.      * repaint last postion
  1955.      */
  1956.  
  1957.     lxi = lxf = -1;
  1958.     tptr->line = &cline;
  1959.     set_text_default(tptr);
  1960.  
  1961.     render_text(tptr);
  1962.  
  1963.     done = 0;
  1964.     do
  1965.       {
  1966.       switch (bit_qread(&val))
  1967.         {
  1968.         case LEFTMOUSE:
  1969.         if (val)
  1970.             handle_mouse(tptr);
  1971.         break;
  1972.         case KEYBD:
  1973.         done = text_keybd(tptr, val);
  1974.         break;
  1975.         case UPARROWKEY:
  1976.         if (val)
  1977.             text_keybd(tptr, 'k');
  1978.         break;
  1979.         case DOWNARROWKEY:
  1980.         if (val)
  1981.             text_keybd(tptr, 'j');
  1982.         break;
  1983.         case LEFTARROWKEY:
  1984.         if (val)
  1985.             text_keybd(tptr, 'h');
  1986.         break;
  1987.         case RIGHTARROWKEY:
  1988.         if (val)
  1989.             text_keybd(tptr, 'l');
  1990.         break;
  1991.         }
  1992.       }
  1993.     while (!done);
  1994.  
  1995.     /*
  1996.      * note resetting of active must appear before hide_form since hide_form
  1997.      * generates an input event(bug?) and by that time line might've been
  1998.      * freed
  1999.      */
  2000.  
  2001.     hide_getcolor();
  2002.     remove_wm_handler(text_wm_handler);
  2003.     active = 0;
  2004.  
  2005. #ifndef  SGL_BUF
  2006.     if (double_buf)
  2007.       {
  2008.       if (lastwme)
  2009.           restore_piece(lxi, lyi, lxf, lyf);
  2010.       swapbuffers();
  2011.       lastwme = 0;
  2012.       }
  2013. #endif
  2014.  
  2015.     restore_piece(lxi, lyi, lxf, lyf);
  2016.  
  2017.     bit_hide_form(textform);
  2018.     freeline(&cline);
  2019.  
  2020. #ifndef NO_NP_DBL
  2021.     free_mat(rastext);
  2022.     rastext = 0;
  2023.     set_magic_pix(0);
  2024.  
  2025. #endif
  2026.  
  2027. #ifdef READSCR
  2028.     free_mat(spp);
  2029.     spp = 0;
  2030. #endif
  2031.  
  2032.     return 0;
  2033. }
  2034.  
  2035. /************************************************************************
  2036.  * Call back routine when the state of size button/counter is changed.
  2037.  * Shadow strength should be a function of of the font size
  2038.  ***********************************************************************/
  2039. /* ARGSUSED */
  2040. static void
  2041. preview_cb(FL_OBJECT * ob, long p)
  2042. {
  2043.     pmatch = fl_get_choice(ob) > 1;
  2044.     fmprintermatch(pmatch);
  2045.     render_text(tptr);
  2046. }
  2047.  
  2048. /* ARGSUSED */
  2049. static void
  2050. fontsize_cb(FL_OBJECT * p, long q)
  2051. {
  2052.     int i;
  2053.  
  2054.     if (p == scounter)
  2055.       {
  2056.       tptr->size = fl_get_counter_value(p);
  2057.       for (i = 0; i < sizeof(fsize) / sizeof(float); i++)
  2058.         {
  2059.         /*
  2060.          * if the size matches one of the predefined size, lit up the
  2061.          * button
  2062.          */
  2063.         fl_set_button(size[i], (fabs(tptr->size - fsize[i]) < 0.05));
  2064.         }
  2065.       }
  2066.     else
  2067.       {
  2068.       tptr->size = fsize[q];
  2069.       fl_set_counter_value(scounter, tptr->size);
  2070.       }
  2071.     render_text(tptr);
  2072. }
  2073.  
  2074. /* ARGSUSED */
  2075. static void
  2076. justification_cb(FL_OBJECT * p, long q)
  2077. {
  2078.     tptr->place = placement = fl_get_choice(p) - 1;
  2079. }
  2080.  
  2081. /* ARGSUSED */
  2082. static void
  2083. select_orientation(FL_OBJECT * p, long q)
  2084. {
  2085.     int i;
  2086.     static float lastc;
  2087.  
  2088.     if (p == rcounter)
  2089.       {
  2090.       tptr->rot = fl_get_counter_value(p);
  2091.       if (fabs(tptr->rot - 360.0) < 0.5)
  2092.         {
  2093.         tptr->rot = 0;
  2094.         fl_set_counter_value(p, 0.0);
  2095.         }
  2096.       for (i = 0; i < sizeof(rangle) / sizeof(float); i++)
  2097.         {
  2098.         /*
  2099.          * if current angle matches predefined angles, lit up the
  2100.          * button else turn it off
  2101.          */
  2102.         fl_set_button(ra[i], (fabs(tptr->rot - rangle[i]) < 0.5));
  2103.         }
  2104.       }
  2105.     else
  2106.       {
  2107.       tptr->rot = rangle[q];
  2108.       fl_set_counter_value(rcounter, tptr->rot);
  2109.       }
  2110.  
  2111.     /* redraw text only if different from last */
  2112.     if (fabs(lastc - tptr->rot) > 0.5)
  2113.     render_text(tptr);
  2114.     lastc = tptr->rot;
  2115. }
  2116.  
  2117. /***************************************************************
  2118.  * New font request
  2119.  **************************************************************/
  2120. /* ARGSUSED */
  2121. static void
  2122. select_font(FL_OBJECT * p, long q)
  2123. {
  2124.     int f = fl_get_choice(fchoice) - 1;
  2125.  
  2126.     if (f >= 0)
  2127.     tptr->findex = f;
  2128.     render_text(tptr);
  2129. }
  2130.  
  2131. /********************************************************************
  2132.  * call back routine when new text is entered
  2133.  ******************************************************************/
  2134. /* ARGSUSED */
  2135. static void
  2136. get_newtext(FL_OBJECT * p, long q)
  2137. {
  2138.     /*
  2139.      * It would appear that hiding a form generates an input event and this
  2140.      * routine will be called. Must turn active off before hiding form
  2141.      */
  2142.     if (!active)
  2143.     return;
  2144.     Strncpy(strbuf, fl_get_input(input), MAXSTR);
  2145.     tokenize(strbuf, tptr->line, tptr->size);
  2146.     text_move(tptr);
  2147. }
  2148.  
  2149. /****************************************************************
  2150.  * Color call back routine. If the image is colormap, counted on
  2151.  * get_color to do the right thing with the colormap index
  2152.  ***************************************************************/
  2153. static int currentq;        /* color current working on */
  2154.  
  2155.  
  2156. static void
  2157. handle_color_change(int cc[])
  2158. {
  2159.     int q = currentq;
  2160.     static int lastq;
  2161.  
  2162.     tptr->col[q][0] = cc[0];
  2163.     tptr->col[q][1] = cc[1];
  2164.     tptr->col[q][2] = cc[2];
  2165.     tptr->col[q][3] = cc[3];
  2166.  
  2167.     if (lastq != q)
  2168.     get_bounding_box(tptr);
  2169.  
  2170.     /* we have to always keep the backbuffer clean */
  2171. #if 1
  2172.     render_text(tptr);
  2173. #else
  2174.     (double_buf ? text_move : text_draw) (tptr);
  2175. #endif
  2176.     lastq = q;
  2177.     diffcolor = 1;
  2178. }
  2179.  
  2180. /*****************************************************************
  2181.  * call back routine for which color currently we are working on
  2182.  ****************************************************************/
  2183. /* ARGSUSED */
  2184. static void
  2185. select_color_cb(FL_OBJECT * p, long q)
  2186. {
  2187.     currentq = q;
  2188.     set_getcolor_cb(handle_color_change);
  2189.     get_color(imgptr, lcol[q], 0);
  2190. }
  2191.  
  2192. /**************************************************************
  2193.  * misc. changes
  2194.  *************************************************************/
  2195. /* ARGSUSED */
  2196. static void
  2197. se_call_back(FL_OBJECT * p, long q)
  2198. {
  2199.     tptr->se = fl_get_choice(effects) - 1;
  2200.     render_text(tptr);
  2201. }
  2202.  
  2203. /* ARGSUSED */
  2204. static void
  2205. frame_bk_cb(FL_OBJECT * p, long q)
  2206. {
  2207.     static int lframe, lbk, leffects;
  2208.  
  2209.     tptr->frame = fl_get_button(frame);
  2210.     tptr->bk = fl_get_button(bk);
  2211.     tptr->se = fl_get_choice(effects) - 1;
  2212.  
  2213.     if (!tptr->bk)
  2214.       {
  2215.       fl_set_object_lcol(col[2], FL_INACTIVE);
  2216.       fl_deactivate_object(col[2]);
  2217.       }
  2218.     else
  2219.       {
  2220.       fl_set_object_lcol(col[2], FL_BLACK);
  2221.       fl_activate_object(col[2]);
  2222.       }
  2223.  
  2224.     if (!tptr->frame)
  2225.       {
  2226.       fl_set_object_lcol(col[1], FL_INACTIVE);
  2227.       fl_deactivate_object(col[1]);
  2228.       }
  2229.     else
  2230.       {
  2231.       fl_set_object_lcol(col[1], FL_BLACK);
  2232.       fl_activate_object(col[1]);
  2233.       }
  2234.  
  2235.     if (lframe - tptr->frame || lbk - tptr->bk || leffects - tptr->se)
  2236.       {
  2237.       render_text(tptr);
  2238.       lframe = tptr->frame;
  2239.       lbk = tptr->bk;
  2240.       leffects = tptr->se;
  2241.       }
  2242. }
  2243.  
  2244. /*****************************************************************
  2245.  * finish up
  2246.  *****************************************************************/
  2247. /* ARGSUSED */
  2248. static void
  2249. text_finish(FL_OBJECT * obj, long q)
  2250. {
  2251.     fl_qenter(KEYBD, 27);
  2252.     /* left do_text do the cleanup */
  2253. }
  2254.  
  2255. /*****************************************************************
  2256.  * Delete all text. Real work is done by del_text. This is just
  2257.  * to get the prototype right
  2258.  *******************************************************************/
  2259.  
  2260. /* ARGSUSED */
  2261. static void
  2262. del_dummy(FL_OBJECT * q, long p)
  2263. {
  2264.  
  2265.     del_text();            /* this routine sets totaltext to zero */
  2266.     imgptr->io->display(imgptr, 0, 1);
  2267.     render_text(tptr);
  2268.  
  2269. }
  2270.  
  2271. /*********************************************************
  2272.  * Request a saving: if q == 1, newline
  2273.  *********************************************************/
  2274. /* ARGSUSED */
  2275. static void
  2276. save_cb(FL_OBJECT * obj, long q)
  2277. {
  2278.     save_text(q);
  2279. }
  2280.  
  2281. /*******************************************************************
  2282.  * Main form
  2283.  ******************************************************************/
  2284. static void
  2285. create_form_text(void)
  2286. {
  2287.     FL_OBJECT *obj;
  2288.     const char *sep = "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=";
  2289.     static int ok;
  2290.     float x, y, dx, dy;
  2291.     int i;
  2292.  
  2293.     if (ok)
  2294.     return;
  2295.     textform = fl_bgn_form(FL_NO_BOX, 295.0, 310.0);
  2296.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 295.0, 310.0, "");
  2297.     fl_set_object_color(obj, 9, 47);
  2298.     obj = fl_add_button(FL_HIDDEN_BUTTON, 0.0, 0.0, 295.0, 310.0, "");
  2299.     fl_set_call_back(obj, help_cb, HELP_TEXT);
  2300.  
  2301.     /* font */
  2302.     fchoice = obj = fl_add_choice(FL_NCH, 60.0, 270.0, 210.0, 25.0, "Font");
  2303.     fl_set_object_boxtype(obj, FL_RSHADOW_BOX);
  2304.     fl_set_call_back(obj, select_font, 0);
  2305.     fl_set_choice_fontsize(obj, 11.0);
  2306.  
  2307.     /* input */
  2308.     input = obj = fl_add_input(FL_NORMAL_INPUT, 10.0, 40.0, 275.0, 20.0, "");
  2309.     fl_set_object_boxtype(obj, FL_BORDER_BOX);
  2310.     fl_set_object_color(obj, 13, 50);
  2311.     fl_set_object_lsize(obj, 8.0);
  2312.     fl_set_call_back(obj, get_newtext, 0);
  2313.  
  2314.     obj = fl_add_text(FL_NT, 5.0, 145.0, 280.0, 10.0, sep);
  2315.     fl_set_object_lsize(obj, FL_SMALL_FONT);
  2316.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  2317.  
  2318.     /* size group */
  2319.     fl_bgn_group();
  2320.     dx = 30.0;
  2321.     dy = 30.0;
  2322.     for (x = 15, y = 190, i = 0; i < 6; i += 2, y -= 20)
  2323.       {
  2324.       size[i] = obj = fl_add_roundbutton(FL_RB, x, y, dx, dy, "");
  2325.       fl_set_object_lsize(obj, FL_SMALL_FONT);
  2326.       fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  2327.       fl_set_call_back(obj, fontsize_cb, i);
  2328.       size[i + 1] = obj = fl_add_roundbutton(FL_RB, x + 65, y, dx, dy, "");
  2329.       fl_set_object_lsize(obj, FL_SMALL_FONT);
  2330.       fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  2331.       fl_set_call_back(obj, fontsize_cb, i + 1);
  2332.       }
  2333.     fl_end_group();
  2334.     scounter = obj = fl_add_counter(FL_NC, 15.0, 220.0, 115.0, 25.0, "Size");
  2335.     fl_set_object_color(obj, 12, 4);
  2336.     fl_set_object_lsize(obj, FL_SMALL_FONT);
  2337.     fl_set_object_align(obj, FL_ALIGN_TOP);
  2338.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  2339.     fl_set_call_back(obj, fontsize_cb, 0);
  2340.  
  2341.     /* direction group */
  2342.     x = 160.0;
  2343.     y = 190.0;
  2344.     dy = 30;
  2345.     fl_bgn_group();
  2346.     for (i = 0; i < 4; i += 2, y -= dy)
  2347.       {
  2348.       ra[i] = obj = fl_add_roundbutton(FL_RB, x, y, 30.0, dy, "");
  2349.       fl_set_object_lsize(obj, FL_SMALL_FONT);
  2350.       fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  2351.       fl_set_call_back(obj, select_orientation, i);
  2352.       ra[i + 1] = obj = fl_add_roundbutton(FL_RB, 225.0, y, 30.0, dy, "");
  2353.       fl_set_object_lsize(obj, FL_SMALL_FONT);
  2354.       fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  2355.       fl_set_call_back(obj, select_orientation, i + 1);
  2356.       }
  2357.  
  2358.     rcounter = obj = fl_add_counter(FL_NC, 155, 220, 120, 25, "Rotation");
  2359.     fl_set_object_color(obj, 12, 4);
  2360.     fl_set_object_lsize(obj, FL_SMALL_FONT);
  2361.     fl_set_object_align(obj, FL_ALIGN_TOP);
  2362.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  2363.     fl_set_call_back(obj, select_orientation, 0);
  2364.     fl_end_group();
  2365.  
  2366.  
  2367.     /* misc group */
  2368.     fl_bgn_group();
  2369.     col[0] = obj = fl_add_roundbutton(FL_NB, 15, 90, 30, 30, "TextColor");
  2370.     fl_set_object_color(obj, 7, 4);
  2371.     fl_set_object_lsize(obj, 10.0);
  2372.     fl_set_call_back(obj, select_color_cb, TC);
  2373.  
  2374.     col[1] = obj = fl_add_roundbutton(FL_NB, 100.0, 90.0, 30, 30, "FrameCol");
  2375.     fl_set_object_color(obj, 7, 4);
  2376.     fl_set_object_lsize(obj, 10.0);
  2377.     fl_set_object_lcol(obj, FL_INACTIVE);
  2378.     fl_deactivate_object(obj);
  2379.     fl_set_call_back(obj, select_color_cb, FC);
  2380.  
  2381.     col[2] = obj = fl_add_roundbutton(FL_NB, 190, 90, 30, 30, "BackgrdCol");
  2382.     fl_set_object_color(obj, 7, 4);
  2383.     fl_set_object_lsize(obj, 10.0);
  2384.     fl_set_call_back(obj, select_color_cb, BC);
  2385.     fl_set_object_lcol(obj, FL_INACTIVE);
  2386.     fl_deactivate_object(obj);
  2387.  
  2388.     frame = obj = fl_add_roundbutton(FL_PB, 100, 115, 30, 30.0, "Frame");
  2389.     fl_set_object_color(obj, 7, 1);
  2390.     fl_set_object_lsize(obj, 10.0);
  2391.     fl_set_call_back(obj, frame_bk_cb, 0);
  2392.     bk = obj = fl_add_roundbutton(FL_PB, 190.0, 115.0, 35, 30, "Background");
  2393.     fl_set_object_color(obj, 7, 1);
  2394.     fl_set_object_lsize(obj, 10.0);
  2395.     fl_set_call_back(obj, frame_bk_cb, 0);
  2396.  
  2397.     /* Special effects */
  2398.     effects = obj = fl_add_choice(FL_NCH, 20, 120.0, 80, 25, "");
  2399.     fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
  2400.     fl_set_choice_fontsize(obj, 10.0);
  2401.     i = 0;
  2402.     while (seffect_name[i])
  2403.       {
  2404.       fl_addto_choice(obj, seffect_name[i]);
  2405.       i++;
  2406.       }
  2407.     fl_set_choice(obj, 1);
  2408.     fl_set_call_back(obj, se_call_back, 0);
  2409.  
  2410.     x = 20.0;
  2411.     y = 65.0;
  2412.     dx = 80;
  2413.     dy = 25;
  2414.     obj = fl_add_choice(FL_NC, x, y, dx, dy, "");
  2415.     fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
  2416.     fl_set_choice_fontsize(obj, 10.0);
  2417.     fl_addto_choice(obj, "Left");
  2418.     fl_addto_choice(obj, "Center");
  2419.     fl_addto_choice(obj, "Right");
  2420.     fl_set_choice(obj, placement + 1);
  2421.     fl_set_call_back(obj, justification_cb, 0);
  2422.  
  2423.     x += dx + 5;
  2424.     obj = fl_add_choice(FL_NC, x, y, dx, dy, "");
  2425.     fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
  2426.     fl_set_choice_fontsize(obj, 10.0);
  2427.     fl_addto_choice(obj, "ScreenFont");
  2428.     fl_addto_choice(obj, "PrinterFont");
  2429.     fl_set_call_back(obj, preview_cb, 0);
  2430.  
  2431.     x += dx + 5;
  2432.     obj = fl_add_choice(FL_NC, x, y, dx, dy, "");
  2433.     fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
  2434.     fl_set_choice_fontsize(obj, 10.0);
  2435.     fl_addto_choice(obj, "Deferred");
  2436.     fl_addto_choice(obj, "Immediate");
  2437.     fl_set_choice(obj, immediate + 1);
  2438.     fl_set_call_back(obj, immediate_cb, 0);
  2439.  
  2440.     fl_end_group();
  2441.  
  2442.     dx = 65.0;
  2443.     dy = 25.0;
  2444.     x = 20;
  2445.     fl_bgn_group();
  2446.  
  2447.     obj = fl_add_button(FL_NB, x, 10.0, dx, dy, "DelAll");
  2448.     fl_set_call_back(obj, del_dummy, 0);
  2449.     fl_set_object_lsize(obj, 10.0);
  2450.     fl_set_object_color(obj, FL_MAGIC1, FL_RED);
  2451.  
  2452.     obj = fl_add_button(FL_NB, x + dx, 10.0, dx, dy, "Done");
  2453.     fl_set_object_lsize(obj, 10.0);
  2454.     fl_set_object_color(obj, FL_MAGIC1, FL_GREEN);
  2455.     fl_set_call_back(obj, text_finish, 0);
  2456.  
  2457.     obj = fl_add_button(FL_NB, x + 2.0 * dx, 10.0, dx, dy, "NewLine");
  2458.     fl_set_object_lsize(obj, 10.0);
  2459.     fl_set_call_back(obj, save_cb, 1);
  2460.  
  2461.     obj = fl_add_button(FL_NB, x + 3.0 * dx, 10.0, dx, dy, "OK");
  2462.     fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
  2463.     fl_set_object_lsize(obj, 10.0);
  2464.     fl_set_call_back(obj, save_cb, 0);
  2465.  
  2466.     fl_end_group();
  2467.     fl_end_form();
  2468.     ok = 1;
  2469. }
  2470.